<?php
namespace WebSwoole;

use Swoole\Coroutine as co;
use Swoole\Http\Server;

ini_set("memory_limit","1024M");

class Http
{
    const VERSION = '1.0';
    public $conn_close = true; 
    public $map = array();

    public $open_log = false;
    public $access_log = array();

    public $autoload = array();
    public $on404 = "";
    public $onAppStart = NULL;
    public $max_request = 10000;
    public $server;

    public function __construct($host, $port)
    {
        $this->server = new Server($host, $port);
        $this->server->set([
            'worker_num' => 4,
            'http_compression' => true,
            'trace_flags' => 1 << 15,
            'log_level' => 0
        ]);
    }
    public function HandleFunc($url, callable $callback){
        if($url != "/"){
            $url = strtolower(trim($url,"/"));
        }
        if(is_callable($callback)){
            if($callback instanceof \Closure){
                $callback = \Closure::bind($callback, $this, get_class());
            }
        }else{
            throw new \Exception('can not HandleFunc');
        }
        $this->map[] = array($url, $callback, 1);
    }
    public function AddFunc($url, callable $callback){
        if($url != "/"){
            $url = strtolower(trim($url,"/"));
        }
        if(is_callable($callback)){
            if($callback instanceof \Closure){
                $callback = \Closure::bind($callback, $this, get_class());
            }
        }else{
            throw new \Exception('can not HandleFunc');
        }
        $this->map[] = array($url,$callback,2);
    }
    public function show_404($response){
        if($this->on404){
            $callback = \Closure::bind($this->on404, $this, get_class());
            call_user_func($callback);
        }else{
            $response->header("Content-Type", "text/html");
            $response->status("404");
            $html = '<html>
                <head><title>404 Not Found</title></head>
                <body bgcolor="white">
                <center><h1>404 Not Found</h1></center>
                <hr><center>Swoole</center>
                </body>
                </html>';
            $response->end($html);
        }
    }
    public function auto_close($conn){
        if(strtolower($_SERVER["server_protocol"]) == "http/1.1"){
            if(isset($_SERVER["http_connection"])){
                if(strtolower($_SERVER["http_connection"]) == "close"){
                    if($this->conn_close){
                        $conn->close();
                    }   
                }
            }
        }else{
            if($_SERVER["http_connection"] == "keep-alive"){
            }else{
                if($this->conn_close) $conn->close();
            }
        }
        $this->access_log[7] = round(microtime_float() - $this->access_log[7],4);
        $log = implode(" - ",$this->access_log);
        if($this->open_log) write_log($log, 'access');
    }
    // 添加默认参数 json_encode的JSON_UNESCAPED_UNICODE参数 使之支持中文 不转义
    public function toJson($data, $option=JSON_UNESCAPED_UNICODE){
        $this->response->header("Content-type", "application/json;charset=utf-8");
        //传入0 不做处理
        if ($option==0){
            return $this->response->end(json_encode($data));
        }else{
            if ($option==JSON_UNESCAPED_UNICODE) {
                if (version_compare(PHP_VERSION,'5.4.0','>=')) {
                    return $this->response->end(json_encode($data,$option));
                }else{
                    return  $this->response->end(json_encode($data));
                }
            }
            //如果传入了别的参数
            return $this->response->end(json_encode($data),$option);
        }
    }
    public function toHtml($data){
        $this->response->header("Content-type", "text/html;charset=utf-8");
        $this->response->end($data);
    }
    public function header($data){
        $this->response->header($data);
    }
    // public function Setcookie($name,$value = '',$maxage = 0,$path = '',$domain = '',$secure = false,$HTTPOnly = false){
    //     Http::setcookie($name,$value,$maxage,$path,$domain,$secure,$HTTPOnly);
    // } 
    // public function onRequest($request, $response)
    // {
    //     $fd = $request->fd;
    //     co::create(function () {
    //         co::sleep(0.1);
    //     });
    //     $response->end(111);
    // }

    public function onAppStart($server){
        $_SERVER = $request->server;
    }
    public function onRequest($request, $response){
        $_SERVER = $request->server;
        $this->access_log[0] = $_SERVER["remote_addr"];
        $this->access_log[1] = date("Y-m-d H:i:s");
        $this->access_log[2] = $_SERVER['request_method'];
        $this->access_log[3] = $_SERVER['request_uri'];
        $this->access_log[4] = $_SERVER['server_protocol'];
        $this->access_log[5] = $_SERVER['request_method']=='GET' ? json_encode($request->get) : json_encode($request->post);
        $this->access_log[6] = 200;
        $this->access_log[7] = microtime_float();
        if(empty($this->map)){
            $str = '404 Not Found!';
            $response->end($str);
            return;
        }
        $this->request  = $request;
        $this->response = $response;
        $url = $_SERVER["request_uri"];
        $pos = stripos($url,"?");
        if ($pos != false) {
            $url = substr($url,0,$pos);
        }
        if($url != "/"){
            $url = strtolower(trim($url,"/"));
        }
        $url_arr = explode("/",$url);
        $class  = empty($url_arr[0]) ? "_default" : $url_arr[0];
        $method = empty($url_arr[1]) ? "_default" : $url_arr[1];
        //su
        $success = false;
        foreach($this->map as $route){
            if($route[2] == 1){//正常路由
                if($route[0] == $url){
                    $callback[] = $route[1];
                    $success = true;
                }
            }else if($route[2] == 2){//中间件
                if($route[0] == "/"){
                    $callback[] = $route[1];
                }else if(stripos($url,$route[0]) === 0){
                    $callback[] = $route[1];
                }
            }
        }
        if(isset($callback) && $success){
            try {
                foreach($callback as $cl){
                    if(call_user_func($cl) === true) break;
                }
            }catch (\Exception $e) {
                // Jump_exit?
                if ($e->getMessage() != 'jump_exit') {
                    $this->access_log[5] = $e;
                }
                $code = $e->getCode() ? $e->getCode() : 500;
                $this->access_log[6] = 500;
            }
        }else{
            $this->show_404($response);
            $code = 404;
            $msg = "class $class not found";
        }
        $this->auto_close($connection);
        // 是否到达最大请求数
        static $request_count = 0;
        if( ++$request_count >= $this->max_request && $this->max_request > 0){
            //Worker::stopAll();
            //echo "server restart!";
        }
    }

    public function run()
    {
        // $this->server->on('Connect', [$this, 'onConnect']);
        if($this->onAppStart != NULL) $this->server->on('start', $this->onAppStart);
        $this->server->on('request', [$this, 'onRequest']);
        // $this->server->on('Close', [$this, 'onClose']);
        $this->server->start();
    }
}

/*
$server = new Server();
Swoole\Coroutine::set(array(
    'max_coroutine' => 1000,
));
$server->run();
*/

